package com.zoran.study.spring.common.advice;

import com.zoran.study.spring.common.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.MessageSource;
import org.springframework.context.NoSuchMessageException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Locale;

public abstract class ExceptionAdvice {

    private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionAdvice.class);

    protected static final ErrorCode INTERNAL_ERROR = CommonErrors.COMMON_INTERNAL_ERROR;

    protected static final ErrorCode ILLEGAL_ARGUMENT = CommonErrors.COMMON_ILLEGAL_ARGUMENT;

    protected static final HttpStatus HTTP_400 = HttpStatus.BAD_REQUEST;

    protected static final HttpStatus HTTP_401 = HttpStatus.UNAUTHORIZED;

    protected static final HttpStatus HTTP_403 = HttpStatus.FORBIDDEN;

    protected static final HttpStatus HTTP_404 = HttpStatus.NOT_FOUND;

    protected static final HttpStatus HTTP_409 = HttpStatus.CONFLICT;

    protected static final HttpStatus HTTP_500 = HttpStatus.INTERNAL_SERVER_ERROR;

    protected static final HttpStatus HTTP_503 = HttpStatus.SERVICE_UNAVAILABLE;

    @Autowired
    @Qualifier("errorMessageSource")
    private MessageSource messageSource;

    /**
     * Create a {@link SingleReasonError} response.
     *
     * @param status
     *            HTTP status code
     * @param error
     *            {@link ErrorCode business error}
     * @param locale
     *            locale
     * @param args
     * @return
     */
    protected ResponseEntity<RestError> toHttpResponse(HttpStatus status, ErrorCode error,
                                                       Locale locale, Object... args) {
        return ResponseEntity.status(status).body(toSingleReasonError(error, locale, args));
    }

    protected RestError toSingleReasonError(ErrorCode error, Locale locale, Object... args) {
        final int errorCode = error.code();
        final String messageKey = error.messageKey();

        String message = null;
        try {
            message = messageSource.getMessage(messageKey, args, locale);
        } catch (NoSuchMessageException ex) {
            LOGGER.warn(ex.getMessage());
        }

        if (!StringUtils.hasText(message)) {
            message = messageKey;
        }

        return new SingleReasonError(errorCode, message);
    }

    /**
     * Create a {@link MultiReasonError} response.
     *
     * @param status
     *            HTTP status code
     * @param errorCode
     *            business error code
     * @param messages
     *            localized error messages
     * @return
     */
    protected ResponseEntity<RestError> toHttpResponse(HttpStatus status, int errorCode,
                                                       List<String> messages) {
        return ResponseEntity.status(status).body(new MultiReasonsError(errorCode, messages));
    }

}
